package com.neusoft.databus.agent.interactive.collect;

import java.net.UnknownHostException;
import java.util.Arrays;
import java.util.Map;
import java.util.stream.Collectors;

import org.jinterop.dcom.common.JIException;
import org.jinterop.dcom.core.JIVariant;
import org.openscada.opc.lib.common.NotConnectedException;
import org.openscada.opc.lib.da.AddFailedException;
import org.openscada.opc.lib.da.DuplicateGroupException;
import org.openscada.opc.lib.da.Group;
import org.openscada.opc.lib.da.Item;
import org.openscada.opc.lib.da.Server;

import com.google.common.collect.Maps;
import com.neusoft.bizcore.web.utils.JsonUtils;
import com.neusoft.bizcore.web.utils.SpringUtil;
import com.neusoft.databus.agent.parser.OpcParser;
import com.neusoft.databus.agent.pool.opc.OpcConnector;
import com.neusoft.databus.common.bean.CommandBean;
import com.neusoft.databus.common.bean.MetricBean;
import com.neusoft.databus.common.exception.DisconnectException;
import com.neusoft.databus.common.parser.Parser;

import lombok.extern.slf4j.Slf4j;

/**
 * OPC collector
 *
 * @author sunchf
 * @date 2019年1月4日 下午5:31:26
 */
@Slf4j
public class OpcOpcCollector extends BasicCollector<Server> {

    public OpcOpcCollector(final Parser parser) {
        super(parser);
        this.connector = SpringUtil.getBean(OpcConnector.class);
    }

    @Override
    public void sendCommand(final CommandBean commandBean) {

        if (OpcOpcCollector.log.isDebugEnabled()) {
            OpcOpcCollector.log.debug("begin to communicate with opc server，{} metrics will be executed",
                    commandBean.getResourceBean().stream().mapToInt(it -> it.getMetrics().size()).sum());
        }
        final Map<String, MetricBean> parsedRequest = ((OpcParser) this.parser).parseCollectRequest(commandBean);
        Map<String, Item> result = Maps.newHashMap();
        final String groupName = String.valueOf(commandBean.getConnectionStr().hashCode());
        Group group;
        try {
            group = this.conn.addGroup(groupName);
        } catch (UnknownHostException | NotConnectedException | JIException e) {
            throw new DisconnectException(e.getMessage(), e);
        } catch (IllegalArgumentException | DuplicateGroupException e) {
            throw new RuntimeException(e.getMessage(), e);
        }
        try {
            final String[] items = parsedRequest.keySet().stream().collect(Collectors.toList())
                    .toArray(new String[] {});
            if (OpcOpcCollector.log.isDebugEnabled()) {
                OpcOpcCollector.log.debug("add items [{}] to default group.",
                        Arrays.asList(items).stream().collect(Collectors.joining(",")));
            }
            result = group.addItems(items);
        } catch (final AddFailedException e) {
            OpcOpcCollector.log.error("opc items errors: {}", JsonUtils.pojoToJson(e.getErrors()));
            result = e.getItems();
        } catch (final JIException e) {
            throw new DisconnectException(e.getMessage(), e);
        }

        if (OpcOpcCollector.log.isDebugEnabled()) {
            OpcOpcCollector.log.debug("receive {} items.", result.size());
        }

        for (final Map.Entry<String, Item> entry : result.entrySet()) {
            JIVariant itemValue;
            try {
                itemValue = entry.getValue().read(false).getValue();
                parsedRequest.get(entry.getKey()).setOriginalValue(itemValue);
            } catch (final JIException e) {
                OpcOpcCollector.log.error(e.getMessage(), e);
            }

        }
        try {
            this.conn.removeGroup(group, false);
        } catch (final Exception e) {
            OpcOpcCollector.log.error(e.getMessage(), e);
        }
    }

}
